package com.firefly.admin.common.utils;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.firefly.admin.common.constant.Constants;
import com.firefly.admin.common.enums.SensitiveTypeEnum;
import com.firefly.admin.common.enums.WhiteListTypeEnum;
import com.firefly.admin.system.entity.FySystemRole;
import com.firefly.admin.config.entity.FySystemSensitiveConfig;
import com.firefly.admin.system.entity.FySystemWhiteList;
import com.firefly.admin.system.service.FySystemRoleService;
import com.firefly.admin.config.service.FySystemSensitiveConfigService;
import com.firefly.admin.system.service.FySystemWhiteListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class SensitiveEncryptUtil {

    @Autowired
    private FySystemSensitiveConfigService configService;

    public static FySystemSensitiveConfigService fySystemSensitiveConfigService;

    @Autowired
    private FySystemWhiteListService whiteListService;

    private static FySystemWhiteListService fySystemWhiteListService;

    @Autowired
    private FySystemRoleService roleService;

    private static FySystemRoleService fySystemRoleService;

    @PostConstruct
    public void init() {
        fySystemSensitiveConfigService = this.configService;
        fySystemWhiteListService = this.whiteListService;
        fySystemRoleService = this.roleService;
    }

    /**
     * 敏感数据脱敏类
     *
     * @param value         原数据
     * @param sensitiveType 敏感类型
     * @return 脱敏后数据
     */
    public static String sensitiveEncrypt(String value, SensitiveTypeEnum sensitiveType) {
        String isOpenSensitiveEncrypt = PropertiesUtil.getValue(Constants.Properties.IS_OPEN_SENSITIVE_ENCRYPT);
        if (Constants.YES.equals(isOpenSensitiveEncrypt) && sensitiveType != null && StringUtils.isNotBlank(value)) {
            if (isInTheWhiteList()) {
                //在白名单内不加密，返回原值
                return value;
            }
            List<FySystemSensitiveConfig> sensitiveConfigList = fySystemSensitiveConfigService.selectListByType(sensitiveType.getType());
            if (!CollectionUtils.isEmpty(sensitiveConfigList)) {
                FySystemSensitiveConfig fySystemSensitiveConfig = sensitiveConfigList.get(0);
                int prefixNoMaskLength = 0;
                int suffixNoMaskLength = 0;
                String replaceCharacter = "*";
                if (fySystemSensitiveConfig != null) {
                    prefixNoMaskLength = fySystemSensitiveConfig.getPrefixNoMaskLength() == null ? 0 : fySystemSensitiveConfig.getPrefixNoMaskLength();
                    suffixNoMaskLength = fySystemSensitiveConfig.getSuffixNoMaskLength() == null ? 0 : fySystemSensitiveConfig.getSuffixNoMaskLength();
                    if (StringUtils.isBlank(fySystemSensitiveConfig.getReplaceCharacter())) {
                        replaceCharacter = fySystemSensitiveConfig.getReplaceCharacter();
                    }
                }
                int length = value.length();
                if (prefixNoMaskLength >= length || suffixNoMaskLength >= length || prefixNoMaskLength + suffixNoMaskLength >= length) {
                    return value;
                }
                if (SensitiveTypeEnum.EMAIL == sensitiveType) {
                    length = value.indexOf("@");
                }
                int replaceLength = length - prefixNoMaskLength - suffixNoMaskLength;
                StringBuilder replaceCharacterStr = new StringBuilder();
                for (int i = 0; i < replaceLength; i++) {
                    replaceCharacterStr.append(replaceCharacter);
                }
                switch (sensitiveType) {
                    case NAME:
                    case ADDRESS:
                        value = value.replaceAll("(\\S{" + prefixNoMaskLength + "})\\S{" + replaceLength + "}(\\S{" + suffixNoMaskLength + "})", "$1" + replaceCharacterStr + "$2");
                        break;
                    case EMAIL:
                        value = value.replaceAll("(\\w{" + prefixNoMaskLength + "})(\\w{" + replaceLength + "})(\\w{" + suffixNoMaskLength + "})(@\\w+\\.[a-z]+(\\.[a-z]+)?)", "$1" + replaceCharacterStr + "$3$4");
                        break;
                    default:
                        value = value.replaceAll("(\\w{" + prefixNoMaskLength + "})\\w{" + replaceLength + "}(\\w{" + suffixNoMaskLength + "})", "$1" + replaceCharacterStr + "$2");
                }
                return value;
            }
        }
        return value;
    }

    public static boolean isInTheWhiteList() {
        try {
            List<FySystemWhiteList> whiteListLists = null;
            Object cacheValue = RedisUtil.hget(Constants.Redis.WHITE_LIST_KEY, WhiteListTypeEnum.SENSITIVE_DATA_NO_ENCRYPT.getWhiteListType());
            if (cacheValue == null) {
                whiteListLists = fySystemWhiteListService.getValueList(WhiteListTypeEnum.SENSITIVE_DATA_NO_ENCRYPT.getWhiteListType());
            } else {
                whiteListLists = new ArrayList<>();
                if (cacheValue instanceof ArrayList<?>) {
                    for (Object o : (List<?>) cacheValue) {
                        whiteListLists.add((FySystemWhiteList) o);
                    }
                }
            }
            if (CollectionUtils.isEmpty(whiteListLists)) {
                return false;
            }
            String token = JwtTokenUtil.getToken();
            if (StringUtils.isBlank(token)) {
                return false;
            }
            Long userId = JwtTokenUtil.getLoginUserId(token);
            List<FySystemRole> roleList = fySystemRoleService.getRoleList(userId);
            List<Long> roleIds = null;
            if (!CollectionUtils.isEmpty(roleList)) {
                roleIds = roleList.stream().map(FySystemRole::getRoleId).collect(Collectors.toList());
            }
            for (FySystemWhiteList fySystemWhiteList : whiteListLists) {
                String valueExtend = fySystemWhiteList.getValueExtend();
                String whiteListValue = fySystemWhiteList.getWhiteListValue();
                if (StringUtils.isBlank(whiteListValue)) {
                    continue;
                }
                List<String> stringList = Arrays.asList(whiteListValue.split(StringPool.COMMA));
                if ("1".equals(valueExtend)) {
                    //账号
                    if (stringList.contains(userId + "")) {
                        return true;
                    }
                } else {
                    //角色
                    if (CollectionUtils.isEmpty(roleIds)) {
                        continue;
                    }
                    for (Long roleId : roleIds) {
                        if (stringList.contains(roleId + "")) {
                            //白名单中包含次账号拥有的角色ID
                            return true;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
